﻿package igz.fleaxy.io {
	import flash.events.EventDispatcher;
	import flash.events.KeyboardEvent;
	import igz.fleaxy.Fleaxy;
	import igz.fleaxy.util.ArrayUtil;

	/**
	 * @author Intelygenz | www.intelygenz.com
	 * 
	 * Clase ocupada de la gestión de teclas
	 */
	public class KeysManager {

//{ STATIC METHODs
		static private var _Current : KeysManager;
		static public function get $Current() : KeysManager {
			return _Current;
		}

		static private function _Init() : void {
			_Current = new KeysManager();
			Fleaxy.$Current.$Stage.addEventListener(KeyboardEvent.KEY_DOWN, _Current._OnKeyDown);
			Fleaxy.$Current.$Stage.addEventListener(KeyboardEvent.KEY_UP, _Current._OnKeyUp);
		}

		/**
		 * Genera una función con una determinada convinación de teclas
		 * 
		 * @param	p_keysCombo convinación de teclas
		 * @param	f_call función a llamar
		 * 
		 * @example KeysManager.$SubscribeToKeysCombo( [Keyboard.CONTROL, Keyboard.SHIFT, Keyboard.F2], _HelpMe );
		 * 
		 */
		static public function $SubscribeToKeysCombo(p_keysCombo:Array, f_call:Function = null) : void {
			if ( _Current==null ) {
				_Init();
			}
			_Current._SubscribeToKeysCombo(p_keysCombo, f_call);
		}

		static public function $IsKeysCombo(p_keysCombo:Array) : Boolean {
			if ( _Current==null ) {
				_Init();
			}
			return _Current._CheckKeys(p_keysCombo);
		}

		static public function $UnsubscribeToKeysCombo(p_keysCombo:Array, f_call:Function = null) : void {
			if ( _Current==null ) {
				_Init();
			}
			_Current._UnsubscribeToKeysCombo(p_keysCombo, f_call);
		}
//}

		private var _KeysCombos:Object;
		private var _PressedKeys:Array;

		public function KeysManager() {
			if ( KeysManager._Current != null ) {
				throw new Error("[KeysManager] ::  Sólo puede haber una instancia de KeysManager manager en un mismo runtime");
			}
			else {
				_KeysCombos  = { "keys" : [], "call" : [] };
				_PressedKeys = new Array();
			}
		}

		protected function _OnKeyUp (p_keyEvent:KeyboardEvent) : void {
			_PressedKeys = ArrayUtil.Remove(_PressedKeys, p_keyEvent.keyCode);
		}

		protected function _OnKeyDown (p_keyEvent:KeyboardEvent) : void {
			var idx:int = _PressedKeys.indexOf( p_keyEvent.keyCode );
			if ( idx == -1 ) {
				_PressedKeys.push( p_keyEvent.keyCode );
			}

			var calls:Array;
			var f:uint, F:uint = _KeysCombos["keys"].length;
			var g:uint, G:uint;
			for (f = 0; f < F; f++ ) {
				if ( _CheckKeys( (_KeysCombos["keys"][f] as String).split("+") ) ) {
					calls = _KeysCombos["call"][f];
					G = calls.length;
					for (g = 0; g < G; g++ ) {
						calls[g](p_keyEvent);
					}
				}
			}

		}

		protected function _SubscribeToKeysCombo(p_keysCombo:Array, f_call:Function = null) : void {
			var keysCombo:String = p_keysCombo.join("+");
			var idx:int = _KeysCombos["keys"].indexOf(keysCombo);
			if (idx == -1 ) {
				_KeysCombos["keys"].push(keysCombo);
				_KeysCombos["call"].push([]);
				idx = _KeysCombos["call"].length -1;
			}
			_KeysCombos["call"][idx].push( f_call );
		}

		protected function _UnsubscribeToKeysCombo(p_keysCombo:Array, f_call:Function = null) : void {
			var keysCombo:String = p_keysCombo.join("+");
			if ( _KeysCombos !=null ) {
				var idx:int = _KeysCombos["keys"].indexOf(keysCombo);
				if ( idx!=-1 ) {
					ArrayUtil.Remove( _KeysCombos["call"][idx], f_call );
				}
			}
		}
		
		protected function _CheckKeys(p_keysCombo:Array ) : Boolean {
			var pressed:uint = 0;
			for each (var keyCode:uint in p_keysCombo ) {
				if ( _PressedKeys.indexOf(keyCode) != -1) {
					pressed++;
				}
			}
			return pressed == p_keysCombo.length;
		}
	}
	
}